Hi, 大家好!
繼昨天的研究,我們目前知道CollectionProxy 涉及到三個objects:owner、target、Reflection
以上篇的例子來看:
irb(main):006:0> User.first.posts.class
User Load (3.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
Post::ActiveRecord_Associations_CollectionProxy < ActiveRecord::Associations::CollectionProxy
owner 為User.first
、target 為posts
,那Reflection object 呢?
我們先來看看在Rails API 搜尋Reflection 可以得到的結果:
從圖裡可看到Reflection 是ActiveRecord 下的一個類別:
Reflection enables the ability to examine the associations and aggregations of Active Record classes and objects. This information, for example, can be used in a form builder that takes an Active Record object and creates input fields for all of the attributes depending on their type and displays the associations to other objects.
**翻譯蒟蒻:Reflection 具有可檢視associations/aggregations 裡物件的能力。而檢視到的資訊可透過form builder 來建立目標的attributes。
猜測這應該解釋了我們為什麼可以這麼建立資料吧:
irb(main):017:0> User.first.posts.create(title: "IThome", body: "IThome rocks")
User Load (0.8ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
(0.2ms) BEGIN
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Post Create (8.0ms) INSERT INTO "posts" ("userId", "title", "body", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["userId", 1], ["title", "IThome"], ["body", "IThome rocks"], ["created_at", "2022-10-01 13:20:49.585730"], ["updated_at", "2022-10-01 13:20:49.585730"]]
(2.6ms) COMMIT
#<Post:0x00007fb4a8338a38> {
:id => 101,
:userId => 1,
:title => "IThome",
:body => "IThome rocks",
:created_at => Sat, 01 Oct 2022 13:20:49 UTC +00:00,
:updated_at => Sat, 01 Oct 2022 13:20:49 UTC +00:00
}
Reflectin Class的第二句說明:
MacroReflection class has info for AggregateReflection and AssociationReflection classes.
**翻譯蒟蒻:MacroReflection 有associations/aggregations 的資訊
可看到這邊還是有點不懂,那MacroReflection 是什麼呢:
ActiveRecord::Reflection::MacroReflection < ActiveRecord::Reflection::AbstractReflection
activerecord/lib/active_record/reflection.rb
Base class for AggregateReflection and AssociationReflection. Objects of AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
**翻譯蒟蒻:結合了這兩個類別的說明,應該是指Reflection 下有個MacroReflection,當使用Reflection 的類別方法時會回傳MacroReflection,上面有associations/aggregations 的資訊
而先看看ActiveRecord::Reflection::MacroReflection 的方法:
大概能理解我們可以這樣做:
ActiveRecord::Reflection::MacroReflection.new(:user, { id: 1 }, ...... }
# 好吧,後面我還不知道怎麼做 XD 但我們能從下方的實體方法來一窺一二
irb(main):008:0> User.reflect_on_association(:posts)
#<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a32dfca8 @name=:posts, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=Post(id: integer, userId: integer, title: text, body: text, created_at: datetime, updated_at: datetime), @plural_name="posts", @type=nil, @foreign_type=nil, @constructable=true, @inverse_name=nil, @class_name="Post", @foreign_key=:userId, @active_record_primary_key="id", @inverse_which_updates_counter_cache=nil>
讓我們先跳去看看Reflection 的類別方法:
.macro -> 可得知彼此(User vs Post)的關聯方法
irb(main):020:0> User.reflect_on_association(:posts).macro
:has_many
.reflect_on_all_associations -> 回傳User 和其他Model 的Reflection
irb(main):021:0> User.reflect_on_all_associations
[
[0] #<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a32dfca8 @name=:posts, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=Post(id: integer, userId: integer, title: text, body: text, created_at: datetime, updated_at: datetime), @plural_name="posts", @type=nil, @foreign_type=nil, @constructable=true, @inverse_name=nil, @class_name="Post", @foreign_key=:userId, @active_record_primary_key="id", @inverse_which_updates_counter_cache=nil>,
[1] #<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a8669220 @name=:todos, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=nil, @plural_name="todos", @type=nil, @foreign_type=nil, @constructable=true>,
[2] #<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a86594d8 @name=:albums, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=nil, @plural_name="albums", @type=nil, @foreign_type=nil, @constructable=true>
]
# 若加上(macro = nil) 在後方當引數,就能指定要查has_one, has_many, belongs_to 的所有Reflection,如:
irb(main):023:0> User.reflect_on_all_associations(:has_many)
# 結果跟上面都一樣,略
研究到此,大概能釐清頭緒,得知CollectionProxy 涉及到的三個objects:owner、target、Reflection,分別是:
User.first
posts
而CollectionProxy 就是綜括以上的結果集啦~~
今天的研究就到這邊,謝謝~~
明天暫定繼續研究CollectionProxy 的方法,和稍微探討一下繼承自Relation 的東東:
ActiveRecord::Associations::CollectionProxy < Relation